Pour en finir avec ces erreurs
Julien Lenormand - Kaizen Solutions
39 slides (non-numérotées)
TODO: vocabulaire module/package
Julien Lenormand
Ingénieur informatique
Pythonista depuis ~2009
python
module toto not found
AttributeError: module 'math' has no attribute 'pi'
Les imports et donc le Path
Objectif : tout comprendre !
import toto
builtins.__import__
The Python
langage reference, The import
statement
import toto
toto
et le
bind dans le module actuel__import__
+ bindtoto = __import__("toto")
(grosse généralisation). . .
import toto as tata
c’est
tata = __import__("toto")
as
sert juste à binder sur un nom
différent (pratique !)import numpy as np
__import__
importlib.import_module
importlib
— The implementation of
import
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return module
PEP 328 – Imports: Multi-Line and Absolute/Relative (2004)
from .titi import tutu
toto/tata.py
qui fait
from ..titi import tutu
import titi.tutu
sys.modules
si "toto"
est présent
sys.meta_path
finders, qui ne se basent pas sur le sys.path
sys.path_hooks
finders qui se basent sur le sys.path
ModuleNotFoundError
Interface :
>>> sys.builtin_module_names
('_abc', '_ast', '_codecs', '_collections', '_functools', '_imp', '_io',
'_locale', '_operator', '_signal', '_sre', '_stat', '_string', '_symtable',
'_thread', '_tracemalloc', '_warnings', '_weakref', 'atexit', 'builtins',
'errno', 'faulthandler', 'gc', 'itertools', 'marshal', 'posix', 'pwd', 'sys',
'time', 'xxsubtype')
```
frozen importlib._bootstrap
par exemple, qui ne contient
que des imports builtin, et implémente le core de la fonctionnalité
d’import de Pythoncpython/Lib/importlib/_bootstrap_external.py
cpython/Tools/build/freeze_modules.py
cpython/Python/frozen_modules/README.txt
Python/importlib.h
(2017)cpython/Makefile.pre.in
Interface :
toto.
__spec__
>>> import sys
>>> sys.__spec__
ModuleSpec(name='sys',
loader=<class '_frozen_importlib.BuiltinImporter'>,
origin='built-in')`
>>> import toto.tutu
>>> toto.tutu.__spec__
ModuleSpec(name='toto.tutu',
loader=<_frozen_importlib_external.SourceFileLoader object at 0x00000225EF0ABD10>
origin='/data/talk-import/toto/tutu.py')
ModuleType
Loader.create_module
: create_module(spec) -> Optional[ModuleType]
__name__
,
__package__
,
__spec__
,__path__
et __file__
optionnels,sys.modules
(avant
son init, pour permettre les imports circulaires)__init__
si ce n’est
pas un namespace
package : Loader.exec_module(module)
: exec_module(module) -> None
sys.modules
et re-raise l’erreurObjects that implement both of these interfaces are referred to as importers - they return themselves when they find that they can load the requested module.
BuiltinImporter
FrozenImporter
zipimporter
def import_module(name, package=None):
"""An approximate implementation of import."""
absolute_name = importlib.util.resolve_name(name, package)
try:
return sys.modules[absolute_name]
except KeyError:
pass
path = None
if '.' in absolute_name:
parent_name, _, child_name = absolute_name.rpartition('.')
parent_module = import_module(parent_name)
path = parent_module.__spec__.submodule_search_locations
for finder in sys.meta_path:
spec = finder.find_spec(absolute_name, path)
if spec is not None:
break
else:
msg = f'No module named {absolute_name!r}'
raise ModuleNotFoundError(msg, name=absolute_name)
module = importlib.util.module_from_spec(spec)
sys.modules[absolute_name] = module
spec.loader.exec_module(module)
if path is not None:
setattr(parent_module, child_name, module)
return module
Non.
__init__
d’un package
?__init__.py
d’un package__all__
import toto
qui
importe tout ce qui est pertinent, plutôt que de devoir chasser dans les
subpackagessys.path
sys.path
module search path :
python path/to/file.py
-> /abs/path/to/
python -m path.to.file
->
/abs/
PYTHONPATH
si défini/usr/lib/python38.zip
(dans un fichier
zip !)/usr/lib/python3.8/site-packages
/home/talk/python-import/venv/lib/site-packages
site
,
pyvenv.cfg
, PYTHONHOME
,
virtual environments, _pth
filessys.path_importer_cache
sys.path
(une liste) : append
/prepend
python
module toto not found
AttributeError: module 'math' has no attribute 'pi'
sys.path
et comparer par
rapport à où est installé le modulesys.path
PYTHONPATH
pour contenir la
racine des sources du projetsys.path.(ap/pre)pend
--system-site-packages
)py
et les venvimportlib.reload
sauf TRES bonne raisonsys.path
et
sys.modules
pour debugimport this
import antigravity
from __future__ import braces
sys.path
Les 4 piliers des problèmes d’import :
importlib
?
Julien Lenormand
Dev et responsable du Pôle Software
julien.lenormand@kaizen-solutions.net
Comment comprendre ?